home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / PCTAGS15.ARJ / CTAG.C < prev    next >
C/C++ Source or Header  |  1991-10-07  |  74KB  |  2,035 lines

  1. /*
  2.  EPSHeader
  3.  
  4.    File: ctag.c
  5.    Author: J. Kercheval
  6.    Created: Sun, 07/14/1991  17:24:44
  7. */
  8. /*
  9.  EPSRevision History
  10.  
  11.    J. Kercheval  Sat, 07/27/1991  22:08:04  creation
  12.    J. Kercheval  Sun, 08/18/1991  20:58:13  completion of CGetToken()
  13.    J. Kercheval  Wed, 08/21/1991  22:34:49  place function recognition
  14.    J. Kercheval  Wed, 08/21/1991  23:11:17  add defines and macros
  15.    J. Kercheval  Wed, 08/21/1991  23:54:33  add typedef and class parsing
  16.    J. Kercheval  Thu, 08/22/1991  23:53:51  add global variables
  17.    J. Kercheval  Thu, 08/22/1991  23:54:05  add enum, struct, union
  18.    J. Kercheval  Thu, 08/22/1991  23:54:28  add globals via typedefs
  19.    J. Kercheval  Sun, 08/25/1991  23:09:28  complete semantic parser
  20.    J. Kercheval  Tue, 08/27/1991  23:28:34  fix bug in typedef, struct, enum and union declarations
  21.    J. Kercheval  Sat, 08/31/1991  23:58:03  add prototype parsing
  22.    J. Kercheval  Tue, 09/03/1991  22:28:55  move many macros to functions
  23.    J. Kercheval  Tue, 09/03/1991  23:05:34  clean code and consolidate to functions
  24.    J. Kercheval  Wed, 09/04/1991  00:16:21  add GNU tag output format support
  25.    J. Kercheval  Sun, 09/08/1991  13:24:53  minor bug fix in function and global variable parser
  26.    J. Kercheval  Sun, 09/08/1991  21:31:06  fix bug in lexical parser
  27.    J. Kercheval  Mon, 09/09/1991  21:49:19  fix bug in function parser
  28.    J. Kercheval  Mon, 09/09/1991  22:39:12  fix buf in define parser
  29.    J. Kercheval  Tue, 09/10/1991  22:06:09  fix typedef parser
  30.    J. Kercheval  Wed, 09/11/1991  02:04:48  add extern symbol recognition
  31.    J. Kercheval  Wed, 09/11/1991  19:49:11  fix bug in function pointer variable declaration
  32.    J. Kercheval  Wed, 09/11/1991  20:38:13  add support for function pointer variable declarations after first declaration
  33.    J. Kercheval  Wed, 09/11/1991  21:51:37  move #directive parsing between semantic and lexical parser
  34.    J. Kercheval  Thu, 09/12/1991  22:44:43  add support for #ifdef blocks to avoid unmatched parens in ToLevelZero parsing
  35.    J. Kercheval  Wed, 09/18/1991  22:05:02  fix bug in GetToken and DiscardLine
  36.    J. Kercheval  Thu, 09/19/1991  22:26:09  fix bug in lexical parser when parsing non C syntax files
  37.    J. Kercheval  Thu, 10/03/1991  18:15:10  add support for Static declarations
  38.    J. Kercheval  Fri, 10/04/1991  11:13:23  add support for tagging enumeration constants
  39.    J. Kercheval  Mon, 10/07/1991  09:36:07  create CParseEnumerationConstants()
  40. */
  41.  
  42. #include <string.h>
  43.  
  44. #include "ctag.h"
  45. #include "tagio.h"
  46. #include "log.h"
  47.  
  48. #define CBUFSIZE 4096
  49. #define MAX_TOKEN_LENGTH 4096
  50.  
  51.  
  52. /* function for determining if character is whitespace */
  53. #define IsWhite(c) ( _C_white_boolean_table[c] )
  54.  
  55. /* the indexed table for white space character lookup */
  56. BOOLEAN _C_white_boolean_table[256];
  57.  
  58. /* list of whitespace characters */
  59. char C_white[] = " \f\t\v\n\r";
  60.  
  61.  
  62. /* function for determining if character is a delimiter */
  63. #define IsDelim(c) ( _C_delim_boolean_table[c] )
  64.  
  65. /* the indexed table for token delimiter lookup */
  66. BOOLEAN _C_delim_boolean_table[256];
  67.  
  68. /* list of token delimiters */
  69. char C_delim[] = " \f\t\v\n\r\"[](){}#;:,.'=-+*/%&|^~!<>?";
  70.  
  71.  
  72. /* function for determining if character is a puncuator */
  73. #define IsPunctuator(c) ( _C_punctuator_boolean_table[c] )
  74.  
  75. /* the indexed table for punctuator character lookup */
  76. BOOLEAN _C_punctuator_boolean_table[256];
  77.  
  78. /* list of punctuators */
  79. char C_declaration_delim[] = "[](){},;=";
  80.  
  81. /*
  82.  * symbol type information is tied to the switches in flags in CTags().  This
  83.  * enum is used to denote the type of the current tag for determining where
  84.  * the appropriate name is located
  85.  */
  86. enum SymbolTypeEnum {
  87.     NOP, Function, ProtoType, Structure, TypeDefinition, Macro,
  88.     Enumeration, EnumerationConstant, Union, GlobalVariable, Class,
  89.     Define, Extern, Static
  90. };
  91.  
  92. /* convenient definition */
  93. typedef enum SymbolTypeEnum SymbolType;
  94.  
  95. /* the current file buffer state */
  96. typedef struct BufferStruct {
  97.     char Cbuf[CBUFSIZE + 1];    /* input buffer for get_token routine */
  98.     char *buffer;               /* current index into the pointer */
  99.     long int token_char_location;       /* current token char location */
  100.     long int token_line_location;       /* current token line in buffer */
  101.     long int token_line_offset; /* offset of current line */
  102.     FILE *infile;
  103. } Buffer;
  104.  
  105.  
  106. /* the current input token state */
  107. typedef struct TokenStruct {
  108.     char sbuf1[MAX_TOKEN_LENGTH];       /* the first token buffer */
  109.     long int charloc1;          /* the char location of sbuf1 */
  110.     long int tokenline1;        /* the line number of sbuf1 */
  111.     long int lineoffset1;       /* the line offset of sbuf1 */
  112.  
  113.     char sbuf2[MAX_TOKEN_LENGTH];       /* the second token buffer */
  114.     long int charloc2;          /* the char location of sbuf2 */
  115.     long int tokenline2;        /* the line number of sbuf2 */
  116.     long int lineoffset2;       /* the line offset of sbuf2 */
  117.  
  118.     char *cur_token;            /* pointer to the current token buffer */
  119.     long int *cur_char_location;/* the location of current token */
  120.     long int *cur_token_line;   /* the line of the current token */
  121.     long int *cur_line_offset;  /* the line offset of the current token */
  122.  
  123.     char *prev_token;           /* pointer to the last token buffer */
  124.     long int *prev_char_location;       /* the location of previous token */
  125.     long int *prev_token_line;  /* the line of the previous token */
  126.     long int *prev_line_offset; /* the line offset of the previous token */
  127.  
  128.     int token_count;            /* tokens seen since last */
  129.     int else_nesting_level;     /* levels deep in #else/#elif nest */
  130.  
  131.     BOOLEAN extern_active;      /* minor state for this statement */
  132.     BOOLEAN static_active;      /* minor state for this statement */
  133. } Token;
  134.  
  135.  
  136. /*----------------------------------------------------------------------------
  137.  *
  138.  * CParserInit() initializes the tables required by the parser. The tables
  139.  * used are a simple boolean index which are true if the character
  140.  * corresponding to the index is a member of the associated table.
  141.  *
  142.  ---------------------------------------------------------------------------*/
  143.  
  144. void CParserInit()
  145. {
  146.     char *s;
  147.     int i;
  148.  
  149.     /* init the entire block to FALSE */
  150.     for (i = 0; i < 256; i++) {
  151.         _C_delim_boolean_table[i] = FALSE;
  152.         _C_white_boolean_table[i] = FALSE;
  153.         _C_punctuator_boolean_table[i] = FALSE;
  154.     }
  155.  
  156.     /* set the characters in the delim set to TRUE */
  157.     for (s = C_delim; *s; s++) {
  158.         _C_delim_boolean_table[*s] = TRUE;
  159.     }
  160.  
  161.     /* set the characters in the white set to TRUE */
  162.     for (s = C_white; *s; s++) {
  163.         _C_white_boolean_table[*s] = TRUE;
  164.     }
  165.  
  166.     /* set the characters in the punctuator set to TRUE */
  167.     for (s = C_declaration_delim; *s; s++) {
  168.         _C_punctuator_boolean_table[*s] = TRUE;
  169.     }
  170. }
  171.  
  172.  
  173. /*----------------------------------------------------------------------------
  174.  *
  175.  * CSymbolWanted() returns true if flags are true for the symbol type passed
  176.  * and false otherwise.  The following mapping is done:
  177.  *
  178.  *      Flag        Type
  179.  *      ---------   --------------
  180.  *      flags->cf   FunctionCall
  181.  *      flags->cp   ProtoType
  182.  *      flags->cs   Structure
  183.  *      flags->ct   TypeDefinition
  184.  *      flags->cm   Macro
  185.  *      flags->ce   Enumeration
  186.  *      flags->ce   EnumerationConstant
  187.  *      flags->cu   Union
  188.  *      flags->cv   GlobalVariable
  189.  *      flags->cc   Class
  190.  *      flags->cd   Define
  191.  *
  192.  ---------------------------------------------------------------------------*/
  193.  
  194. BOOLEAN CSymbolWanted(SymbolType type, Flags * flags)
  195. {
  196.     switch (type) {
  197.             case Function:
  198.             if (flags->cf)
  199.                 return TRUE;
  200.             break;
  201.         case ProtoType:
  202.             if (flags->cp)
  203.                 return TRUE;
  204.             break;
  205.         case GlobalVariable:
  206.             if (flags->cv)
  207.                 return TRUE;
  208.             break;
  209.         case Define:
  210.             if (flags->cd)
  211.                 return TRUE;
  212.             break;
  213.         case Macro:
  214.             if (flags->cm)
  215.                 return TRUE;
  216.             break;
  217.         case Structure:
  218.             if (flags->cs)
  219.                 return TRUE;
  220.             break;
  221.         case TypeDefinition:
  222.             if (flags->ct)
  223.                 return TRUE;
  224.             break;
  225.         case Enumeration:
  226.             if (flags->ce)
  227.                 return TRUE;
  228.             break;
  229.         case EnumerationConstant:
  230.             if (flags->ck)
  231.                 return TRUE;
  232.             break;
  233.         case Union:
  234.             if (flags->cu)
  235.                 return TRUE;
  236.             break;
  237.         case Class:
  238.             if (flags->cc)
  239.                 return TRUE;
  240.             break;
  241.         default:
  242.             return FALSE;
  243.             break;
  244.     }
  245.  
  246.     /* not reached */
  247.     return FALSE;
  248. }
  249.  
  250.  
  251. /*----------------------------------------------------------------------------
  252.  *
  253.  * CTokenType() takes the token passed and determines if the token is a
  254.  * special token.  Special tokens require specialized handling in the parser.
  255.  * The function returns the type of token according to the SymbolTypeEnum
  256.  * enumeration.  This routine can only tell so much from one symbol but will
  257.  * return some type for all the *interesting* tokens.  Anything that is
  258.  * loosely defined is given back with the closest type available and the
  259.  * parser must give it contextual meaning
  260.  *
  261.  ---------------------------------------------------------------------------*/
  262.  
  263. SymbolType CTokenType(char *token)
  264. {
  265.     char start[] = "cestu";     /* list of starting characters of symbols */
  266.  
  267.     /* look for dirty rejection */
  268.     if (!strchr(start, token[0]))
  269.         return NOP;
  270.  
  271.     /* structure declarations */
  272.     if (!strcmp(token, "struct"))
  273.         return Structure;
  274.  
  275.     /* type declaration */
  276.     if (!strcmp(token, "typedef"))
  277.         return TypeDefinition;
  278.  
  279.     /* enumeration declaration */
  280.     if (!strcmp(token, "enum"))
  281.         return Enumeration;
  282.  
  283.     /* union declaration */
  284.     if (!strcmp(token, "union"))
  285.         return Union;
  286.  
  287.     /* class declaration */
  288.     if (!strcmp(token, "class"))
  289.         return Class;
  290.  
  291.     /* extern declaration */
  292.     if (!strcmp(token, "extern"))
  293.         return Extern;
  294.  
  295.     /* static declaration */
  296.     if (!strcmp(token, "static"))
  297.         return Static;
  298.  
  299.     /* do not recognize it as anything special */
  300.     return NOP;
  301. }
  302.  
  303.  
  304. /*----------------------------------------------------------------------------
  305.  *
  306.  * CIsDeclarationToken() takes the token passed and determines if the token
  307.  * is a declaration keyword used in C.  The user may define new declaration
  308.  * keywords via use of the typedef keyword.  This alters the syntax of C.  If
  309.  * the syntax is changed in this way it is probable that this routine would
  310.  * not return the correct value.  For the standard uses of this routine that
  311.  * information should not hinder performance for the vast majority of the
  312.  * cases.
  313.  *
  314.  ---------------------------------------------------------------------------*/
  315.  
  316. #define SYMBOL_SIZE 20
  317.  
  318. BOOLEAN CIsDeclarationToken(char *token)
  319. {
  320.     char token_list[][SYMBOL_SIZE] =
  321.     {
  322.         "*ivclsdfuaretp_hn",    /* list of starting characters of symbols
  323.                                  * below */
  324.         "*",                    /* pointer */
  325.         "int",                  /* integer declaration */
  326.         "void",                 /* void type */
  327.         "char",                 /* character */
  328.         "long",                 /* long integer */
  329.         "short",                /* short integer */
  330.         "double",               /* double floating point */
  331.         "float",                /* floating point */
  332.         "signed",               /* signed integer */
  333.         "unsigned",             /* unsigned integer */
  334.         "auto",                 /* auto variable (local duration) */
  335.         "register",             /* register variable */
  336.         "static",               /* static variable */
  337.         "struct",               /* structure define */
  338.         "union",                /* union define */
  339.         "enum",                 /* enum defined */
  340.         "typedef",              /* type definition */
  341.         "const",                /* constant variable */
  342.         "extern",               /* external declaration */
  343.         "class",                /* class declaration */
  344.         "friend",               /* class modifier */
  345.         "private",              /* class modifier */
  346.         "protected",            /* class modifier */
  347.         "public",               /* class modifier */
  348.         "volatile",             /* Compiler warning */
  349.         "_based",               /* pointer type */
  350.         "_cdecl",               /* parameter calling sequence, C style */
  351.         "cdecl",                /* parameter calling sequence, C style */
  352.         "_far",                 /* pointer type */
  353.         "far",                  /* pointer type */
  354.         "_huge",                /* pointer type */
  355.         "huge",                 /* pointer type */
  356.         "_near",                /* pointer type */
  357.         "near",                 /* pointer type */
  358.         "_pascal",              /* parameter calling sequence, PASCAL style */
  359.         "pascal",               /* parameter calling sequence, PASCAL style */
  360.         "_fortran",             /* parameter calling sequence, FORTRAN style */
  361.         "_fastcall",            /* parameter calling sequence, via registers */
  362.         "\0"
  363.     };
  364.  
  365.     int index;
  366.  
  367.     /* look for dirty rejection */
  368.     if (!strchr(token_list[0], token[0]))
  369.         return FALSE;
  370.  
  371.     /* march through array until membership is determined */
  372.     for (index = 1; *token_list[index]; (index)++) {
  373.  
  374.         /* return true if token found */
  375.         if (!strcmp(token, token_list[index])) {
  376.             return TRUE;
  377.         }
  378.     }
  379.  
  380.     /* did not find it */
  381.     return FALSE;
  382. }
  383.  
  384.  
  385. /*----------------------------------------------------------------------------
  386.  *
  387.  * COutputToken() will output a token of a given type.  The token is output
  388.  * if the passed token type is requested from the command line.
  389.  *
  390.  ---------------------------------------------------------------------------*/
  391.  
  392. void COutputToken(Token * token, Buffer * token_buffer,
  393.                    SymbolType token_type, FILE * outfile,
  394.                    char *infname, Flags * flags)
  395. {
  396.     char line[MAX_TOKEN_LENGTH];/* the line for use with GNU output format */
  397.  
  398.     long int old_offset;        /* the previous value of the file ptr */
  399.     int line_length;            /* the length of the line */
  400.  
  401.     /* init */
  402.     line[0] = '\0';
  403.  
  404.     /* check that the symbol is wanted and output it if so */
  405.     if (CSymbolWanted(token_type, flags)) {
  406.  
  407.         /* return if external and externals not wanted */
  408.         if (token->extern_active) {
  409.             if (!flags->cx) {
  410.                 if (token_type != Function &&
  411.                     token_type != Define &&
  412.                     token_type != Macro) {
  413.                     return;
  414.                 }
  415.             }
  416.         }
  417.  
  418.         /* return if static and statics are not wanted */
  419.         if (token->static_active) {
  420.             if (!flags->ci) {
  421.                 if (token_type != Define &&
  422.                     token_type != Macro) {
  423.                     return;
  424.                 }
  425.             }
  426.         }
  427.  
  428.         /* if GNU output is specified then we need to output the full line */
  429.         if (flags->og) {
  430.             /* store the current file offset, move to the line offset, read
  431.              * the line into a buffer and restore the file offset */
  432.             old_offset = ftell(token_buffer->infile);
  433.             if (fseek(token_buffer->infile,
  434.                       *(token->prev_line_offset), SEEK_SET)) {
  435.                 log_message("# COutputToken() -- internal error - continuing");
  436.             }
  437.             else {
  438.                 fgets(line, MAX_TOKEN_LENGTH, token_buffer->infile);
  439.                 line_length = strlen(line);
  440.                 if (line[line_length - 1] == '\n') {
  441.                     line[line_length - 1] = '\0';
  442.                 }
  443.                 if (fseek(token_buffer->infile, old_offset, SEEK_SET)) {
  444.                     log_message("# COutputToken() -- internal error - continuing");
  445.                 }
  446.             }
  447.         }
  448.  
  449.         OutputTag(outfile, line,
  450.                   token->prev_token, infname,
  451.                   *(token->prev_token_line),
  452.                   *(token->prev_char_location) -
  453.                   strlen(token->prev_token), flags);
  454.     }
  455. }
  456.  
  457.  
  458. /*----------------------------------------------------------------------------
  459.  *
  460.  * CGetToken() will obtain the next token in the line pointed to by lptr
  461.  * and in addition will return FALSE if EOL is reached or a comment character
  462.  * is the first non whitespace character found.  This routine is passed an
  463.  * inbut buffer (Cbuf) and a current pointer into the buffer.  It is the
  464.  * responsibility of this routine to refill the buffer if required.  Quoted
  465.  * strings and single quoted characters are returned as a single token.
  466.  * Comments are completely ignored by this parser.  The token will not exceed
  467.  * max_token_length - 1 in length (not including the end of line delimiter)
  468.  *
  469.  ---------------------------------------------------------------------------*/
  470.  
  471. BOOLEAN CGetToken(FILE * infile,
  472.                    char **buffer,
  473.                    char *Cbuf,
  474.                    char *token,
  475.                    int max_token_length,
  476.                    long int *line_number,
  477.                    long int *char_number,
  478.                    long int *line_offset)
  479. {
  480.     typedef enum parser_state { /* a state of the lexical parser */
  481.         Parse, BeginCommentMaybe, InComment, InCommentEndMaybe, InCPPComment,
  482.         InQuoteNormal, InQuoteLiteral, InSingleQuoteNormal,
  483.         InSingleQuoteLiteral, EndSingleQuote, WhiteSpace, Exit
  484.     } State;
  485.  
  486.     State current_state;        /* the current state of the parser */
  487.  
  488.     char c;                     /* the current character being examined */
  489.     char *t;                    /* pointer into token */
  490.  
  491.     int token_length;           /* the current token length cannot exceed max
  492.                                  * token length */
  493.  
  494.     /* init */
  495.     current_state = WhiteSpace;
  496.     t = token;
  497.     *t = '\0';
  498.     token_length = 0;
  499.  
  500.     /* parse the file for the next token */
  501.     while (TRUE) {
  502.  
  503.         c = **buffer;
  504.  
  505.         /* if the buffer has been completely used, refill the buffer, I make
  506.          * the tacit assumption here that the null character is not a member
  507.          * of the source file */
  508.         if (!c) {
  509.             *buffer = Cbuf;
  510.             if (FillBuffer(infile, Cbuf,
  511.                            (long int) CBUFSIZE)) {
  512.                 c = **buffer;
  513.             }
  514.             else {
  515.  
  516.                 /* return the token if it exists */
  517.                 if (t != token) {
  518.                     *t = '\0';
  519.                     return TRUE;
  520.                 }
  521.                 else
  522.                     return FALSE;
  523.             }
  524.         }
  525.  
  526.         /* react on the state machine */
  527.         switch (current_state) {
  528.  
  529.             case Parse:
  530.                 switch (c) {
  531.  
  532.                     case '/':
  533.  
  534.                         /* return if we already have a token */
  535.                         if (t != token) {
  536.                             (*buffer)--;
  537.                             (*char_number)--;
  538.                             current_state = Exit;
  539.                         }
  540.                         else {
  541.                             /* this may be the begin if a comment or the
  542.                              * division symbol, read the next character after
  543.                              * verifying it the buffer doesn't need refilling */
  544.                             current_state = BeginCommentMaybe;
  545.                             *t = c;
  546.                         }
  547.                         break;
  548.  
  549.                     case '\"':
  550.  
  551.                         /* return if we already have a token */
  552.                         if (t != token) {
  553.                             (*buffer)--;
  554.                             (*char_number)--;
  555.                             current_state = Exit;
  556.                         }
  557.                         else {
  558.                             current_state = InQuoteNormal;
  559.                             *t++ = c;
  560.                             token_length++;
  561.                         }
  562.                         break;
  563.  
  564.                     case '\'':
  565.  
  566.                         /* return if we already have a token */
  567.                         if (t != token) {
  568.                             (*buffer)--;
  569.                             (*char_number)--;
  570.                             current_state = Exit;
  571.                         }
  572.                         else {
  573.                             current_state = InSingleQuoteNormal;
  574.                             *t++ = c;
  575.                             token_length++;
  576.                         }
  577.                         break;
  578.  
  579.                     default:
  580.  
  581.                         /* if it is a delimiter than stop processing */
  582.                         if (IsDelim(c)) {
  583.  
  584.                             /* if a token exists then back up in buffer */
  585.                             if (t != token) {
  586.                                 (*buffer)--;
  587.                                 (*char_number)--;
  588.                             }
  589.                             else {
  590.                                 *t++ = c;
  591.                                 token_length++;
  592.                             }
  593.                             current_state = Exit;
  594.                         }
  595.                         else {
  596.  
  597.                             /* normal character, store it in the token */
  598.                             *t++ = c;
  599.                             token_length++;
  600.                         }
  601.                         break;
  602.                 }
  603.                 break;
  604.  
  605.             case WhiteSpace:
  606.  
  607.                 /* pass over whitespace, backup one char if no longer in
  608.                  * white space region */
  609.                 if (!IsWhite(c)) {
  610.                     current_state = Parse;
  611.                     (*buffer)--;
  612.                     (*char_number)--;
  613.                 }
  614.                 else {
  615.  
  616.                     /* check for newline */
  617.                     if (c == '\n') {
  618.                         (*line_number)++;
  619.                         *line_offset = *char_number + *line_number;
  620.                     }
  621.                 }
  622.                 break;
  623.  
  624.             case BeginCommentMaybe:
  625.                 switch (c) {
  626.  
  627.                     case '/':
  628.                         current_state = InCPPComment;
  629.                         break;
  630.  
  631.                     case '*':
  632.                         current_state = InComment;
  633.                         break;
  634.  
  635.                     default:
  636.                         t++;
  637.                         token_length++;
  638.                         (*buffer)--;
  639.                         (*char_number)--;
  640.                         current_state = Exit;
  641.                         break;
  642.                 }
  643.                 break;
  644.  
  645.             case InComment:
  646.                 switch (c) {
  647.  
  648.                     case '*':
  649.                         /* this is potentially the end of the comment */
  650.                         current_state = InCommentEndMaybe;
  651.                         break;
  652.  
  653.                     case '\n':
  654.                         /* new line just increment state variables */
  655.                         (*line_number)++;
  656.                         *line_offset = *char_number + *line_number;
  657.                         break;
  658.  
  659.                     default:
  660.                         break;
  661.                 }
  662.                 break;
  663.  
  664.             case InCommentEndMaybe:
  665.                 switch (c) {
  666.  
  667.                     case '/':
  668.                         /* this is indeed the end of the comment */
  669.                         current_state = WhiteSpace;
  670.                         break;
  671.  
  672.                     case '*':
  673.                         /* this is also perhaps the end of comment */
  674.                         break;
  675.  
  676.                     case '\n':
  677.                         /* new line just increment state variables */
  678.                         (*line_number)++;
  679.                         *line_offset = *char_number + *line_number;
  680.  
  681.                     default:
  682.                         /* still part of the current comment */
  683.                         current_state = InComment;
  684.                         break;
  685.                 }
  686.                 break;
  687.  
  688.             case InCPPComment:
  689.                 if (c == '\n') {
  690.                     current_state = WhiteSpace;
  691.                     (*line_number)++;
  692.                     *line_offset = *char_number + *line_number;
  693.                 }
  694.                 break;
  695.  
  696.             case InQuoteNormal:
  697.                 switch (c) {
  698.  
  699.                     case '\"':
  700.                         /* end of InQuoteNormal state */
  701.                         current_state = Exit;
  702.                         break;
  703.  
  704.                     case '\\':
  705.                         /* InQuoteLiteral state */
  706.                         current_state = InQuoteLiteral;
  707.                         break;
  708.  
  709.                     default:
  710.                         /* normal dull behavior */
  711.                         break;
  712.                 }
  713.                 *t++ = c;
  714.                 token_length++;
  715.                 break;
  716.  
  717.             case InQuoteLiteral:
  718.                 /* this char is simply copied */
  719.                 current_state = InQuoteNormal;
  720.                 *t++ = c;
  721.                 token_length++;
  722.                 break;
  723.  
  724.             case InSingleQuoteNormal:
  725.                 switch (c) {
  726.  
  727.                     case '\\':
  728.                         /* InQuoteLiteral state */
  729.                         current_state = InSingleQuoteLiteral;
  730.                         break;
  731.  
  732.                     default:
  733.                         /* Just copy the character and move to close quote */
  734.                         current_state = EndSingleQuote;
  735.                         break;
  736.                 }
  737.                 *t++ = c;
  738.                 token_length++;
  739.                 break;
  740.  
  741.             case InSingleQuoteLiteral:
  742.                 /* this char is simply copied */
  743.                 current_state = EndSingleQuote;
  744.                 *t++ = c;
  745.                 token_length++;
  746.                 break;
  747.  
  748.             case EndSingleQuote:
  749.  
  750.                 /* end of InSingleQuote states */
  751.                 current_state = Exit;
  752.                 *t++ = c;
  753.                 token_length++;
  754.                 break;
  755.  
  756.             case Exit:
  757.                 *t = '\0';
  758.                 return TRUE;
  759.                 break;
  760.  
  761.             default:            /* not reached */
  762.                 break;
  763.         }
  764.  
  765.         /* if the token_length has gotten too large then return */
  766.         if (token_length == max_token_length - 1) {
  767.             *t = '\0';
  768.             return TRUE;
  769.         }
  770.  
  771.         /* move to the next buffer location */
  772.         (*buffer)++;
  773.         (*char_number)++;
  774.     }
  775. }
  776.  
  777.  
  778. /*----------------------------------------------------------------------------
  779.  *
  780.  * CFillToken() will obtain the next lexical parser from the buffer and move
  781.  * the token into the Token structure.  TRUE is returned if the lexical
  782.  * parser returns TRUE, otherwise FALSE is returned.
  783.  *
  784.  ---------------------------------------------------------------------------*/
  785.  
  786. BOOLEAN CFillToken(Token * token, Buffer * token_buffer)
  787. {
  788.     BOOLEAN token_found;
  789.  
  790.     /* obtain the next token */
  791.     token_found = CGetToken(token_buffer->infile,
  792.                             &(token_buffer->buffer),
  793.                             token_buffer->Cbuf, token->cur_token,
  794.                             MAX_TOKEN_LENGTH,
  795.                             &(token_buffer->token_line_location),
  796.                             &(token_buffer->token_char_location),
  797.                             &(token_buffer->token_line_offset));
  798.  
  799.     /* if one is around then update the state for that token */
  800.     if (token_found) {
  801.         /* update location variables */
  802.         *(token->cur_char_location) =
  803.             token_buffer->token_char_location;
  804.         *(token->cur_token_line) =
  805.             token_buffer->token_line_location;
  806.         *(token->cur_line_offset) =
  807.             token_buffer->token_line_offset;
  808.     }
  809.  
  810.     return token_found;
  811. }
  812.  
  813.  
  814. /*----------------------------------------------------------------------------
  815.  *
  816.  * CTokenSwap() will swap the token variables and set the prev_ variables
  817.  * correctly
  818.  *
  819.  ---------------------------------------------------------------------------*/
  820.  
  821. void CTokenSwap(Token * token)
  822. {
  823.     char *charswap;             /* temporary swap variable */
  824.     long int *longintswap;      /* temporary swap variable */
  825.  
  826.     /* swap the active token string */
  827.     charswap = token->cur_token;
  828.     token->cur_token = token->prev_token;
  829.     token->prev_token = charswap;
  830.  
  831.     /* swap the active character location */
  832.     longintswap = token->cur_char_location;
  833.     token->cur_char_location = token->prev_char_location;
  834.     token->prev_char_location = longintswap;
  835.  
  836.     /* swap the active line */
  837.     longintswap = token->cur_token_line;
  838.     token->cur_token_line = token->prev_token_line;
  839.     token->prev_token_line = longintswap;
  840.  
  841.     /* swap the active line offset */
  842.     longintswap = token->cur_line_offset;
  843.     token->cur_line_offset = token->prev_line_offset;
  844.     token->prev_line_offset = longintswap;
  845. }
  846.  
  847.  
  848. /*----------------------------------------------------------------------------
  849.  *
  850.  * CDiscardLine() will move past all the characters up to the next EOL that
  851.  * is not preceded by a line continuation character.  This routine will
  852.  * return TRUE if there was a '(' character as the first character.  This
  853.  * return value is useful for determining if #defines are macros or simple
  854.  * defines.
  855.  *
  856.  ---------------------------------------------------------------------------*/
  857.  
  858. BOOLEAN CDiscardLine(FILE * infile, char **buffer, char *Cbuf,
  859.                       long int *line_number, long int *char_number,
  860.                       long int *line_offset)
  861. {
  862.     char c;                     /* the current character being examined */
  863.  
  864.     BOOLEAN line_continue;      /* TRUE if line continuation true */
  865.     BOOLEAN is_macro;           /* TRUE if the first delimiter char is '(' */
  866.     BOOLEAN first_char;         /* TRUE when first character is active */
  867.  
  868.     /* init */
  869.     c = '\0';
  870.     line_continue = FALSE;
  871.     is_macro = FALSE;
  872.     first_char = TRUE;
  873.  
  874.     /* loop until non continued EOL encountered */
  875.     do {
  876.  
  877.         /* handle the newline */
  878.         if (c == '\n') {
  879.             line_continue = FALSE;
  880.             (*line_number)++;
  881.             *line_offset = *char_number + *line_number + 1;
  882.         }
  883.  
  884.         c = **buffer;
  885.         (*buffer)++;
  886.         (*char_number)++;
  887.  
  888.         /* if the buffer has been completely used, refill the buffer, I make
  889.          * the tacit assumption here that the null character is not a member
  890.          * of the source file */
  891.         if (!c) {
  892.             *buffer = Cbuf;
  893.             if (FillBuffer(infile, Cbuf,
  894.                            (long int) CBUFSIZE)) {
  895.                 c = **buffer;
  896.                 (*char_number)--;
  897.             }
  898.             else {
  899.  
  900.                 /* end of file reached */
  901.                 return is_macro;
  902.             }
  903.         }
  904.  
  905.         if (c == '\\')
  906.             line_continue = TRUE;
  907.  
  908.         if (first_char) {
  909.             if (c == '(')
  910.                 is_macro = TRUE;
  911.             first_char = FALSE;
  912.         }
  913.  
  914.     } while (c != '\n' || line_continue);
  915.  
  916.     (*line_number)++;
  917.     return is_macro;
  918. }
  919.  
  920.  
  921. /*----------------------------------------------------------------------------
  922.  *
  923.  * CParseDefine() will parse macros and defines in standard C syntax and
  924.  * distinguish between a macro and a define, if there is a punctuator '(' as
  925.  * the first character after the token, then it is a macro.
  926.  *
  927.  ---------------------------------------------------------------------------*/
  928.  
  929. void CParseDefine(Token * token, Buffer * token_buffer,
  930.                    FILE * outfile, char *infname, Flags * flags)
  931. {
  932.     SymbolType tmptype;         /* a temporay type variable */
  933.  
  934.     BOOLEAN token_found;
  935.     BOOLEAN is_macro;
  936.  
  937.     token_found = CFillToken(token, token_buffer);
  938.     if (token_found) {
  939.  
  940.         /* save the previous values */
  941.         CTokenSwap(token);
  942.  
  943.         /* get rid of the rest of the line and return the define type */
  944.         is_macro =
  945.             CDiscardLine(token_buffer->infile,
  946.                          &(token_buffer->buffer),
  947.                          token_buffer->Cbuf,
  948.                          &(token_buffer->token_line_location),
  949.                          &(token_buffer->token_char_location),
  950.                          &(token_buffer->token_line_offset));
  951.  
  952.         /* react on the token */
  953.         if (is_macro) {
  954.             tmptype = Macro;
  955.         }
  956.         else {
  957.             tmptype = Define;
  958.         }
  959.  
  960.         /* output the token */
  961.         COutputToken(token, token_buffer, tmptype,
  962.                      outfile, infname, flags);
  963.     }
  964. }
  965.  
  966.  
  967. /*----------------------------------------------------------------------------
  968.  *
  969.  * CParsePreprocessorDirective() will parse preprocessor directives in
  970.  * standard C syntax
  971.  *
  972.  ---------------------------------------------------------------------------*/
  973.  
  974. void CParsePreprocessorDirective(Token * token, Buffer * token_buffer,
  975.                                FILE * outfile, char *infname, Flags * flags)
  976. {
  977.     BOOLEAN token_found;
  978.  
  979.     token_found = CFillToken(token, token_buffer);
  980.     if (token_found) {
  981.  
  982.         /* deal with a define directive */
  983.         if (!strcmp(token->cur_token, "define")) {
  984.             CParseDefine(token, token_buffer, outfile, infname, flags);
  985.         }
  986.         else {
  987.  
  988.             /* increment the else block level pointer */
  989.             if (!strcmp(token->cur_token, "else")) {
  990.                 token->else_nesting_level++;
  991.             }
  992.             else {
  993.                 /* decrement the else block level pointer */
  994.                 if (!strcmp(token->cur_token, "endif")) {
  995.                     if (token->else_nesting_level)
  996.                         token->else_nesting_level--;
  997.                 }
  998.                 else {
  999.  
  1000.                     /* if an else has not already been seen then increment
  1001.                      * the level */
  1002.                     if (!strcmp(token->cur_token, "elif")) {
  1003.                         token->else_nesting_level++;
  1004.                     }
  1005.                 }
  1006.             }
  1007.  
  1008.             /* remove the rest of the directive line including line
  1009.              * continuation characters */
  1010.             CDiscardLine(token_buffer->infile,
  1011.                          &(token_buffer->buffer),
  1012.                          token_buffer->Cbuf,
  1013.                          &(token_buffer->token_line_location),
  1014.                          &(token_buffer->token_char_location),
  1015.                          &(token_buffer->token_line_offset));
  1016.         }
  1017.     }
  1018. }
  1019.  
  1020.  
  1021. /*----------------------------------------------------------------------------
  1022.  *
  1023.  * CNextToken() will obtain the next token in the buffer and update the
  1024.  * appropriate variables.
  1025.  *
  1026.  ---------------------------------------------------------------------------*/
  1027.  
  1028. BOOLEAN CNextToken(Token * token, Buffer * token_buffer, FILE * outfile,
  1029.                     char *infname, Flags * flags)
  1030. {
  1031.     BOOLEAN token_found;
  1032.     BOOLEAN cycle;
  1033.  
  1034.     do {
  1035.         /* obtain the next token */
  1036.         token_found = CFillToken(token, token_buffer);
  1037.  
  1038.         /* check for preprocessing directives and parse them if found */
  1039.         if (token->cur_token[0] == '#' && token_found) {
  1040.  
  1041.             /* parse the directive and loop back to get another token */
  1042.             CParsePreprocessorDirective(token, token_buffer,
  1043.                                         outfile, infname, flags);
  1044.             cycle = TRUE;
  1045.         }
  1046.         else {
  1047.  
  1048.             /* we found a token to pass to the semantic parser */
  1049.             cycle = FALSE;
  1050.         }
  1051.     } while (cycle);
  1052.  
  1053.     /* return it */
  1054.     return token_found;
  1055. }
  1056.  
  1057.  
  1058. /*----------------------------------------------------------------------------
  1059.  *
  1060.  * CToLevelZero() will increment the nesting level and then parse tokens
  1061.  * until level zero has been reached again.  If tokens are no longer
  1062.  * available this loop will stop.
  1063.  *
  1064.  ---------------------------------------------------------------------------*/
  1065.  
  1066. void CToLevelZero(Token * token, Buffer * token_buffer,
  1067.                    FILE * outfile, char *infname, Flags * flags)
  1068. {
  1069.     char open_brace[] = "{[(";  /* open brace set */
  1070.     char close_brace[] = ")]}"; /* close brace set */
  1071.  
  1072.     int nesting_level = 1;
  1073.  
  1074.     token->else_nesting_level = 0;
  1075.  
  1076.     while (nesting_level) {
  1077.         if (CGetToken(token_buffer->infile, &(token_buffer->buffer),
  1078.                       token_buffer->Cbuf, token->cur_token,
  1079.                       MAX_TOKEN_LENGTH,
  1080.                       &(token_buffer->token_line_location),
  1081.                       &(token_buffer->token_char_location),
  1082.                       &(token_buffer->token_line_offset))) {
  1083.             if (token->cur_token[0] == '#') {
  1084.                 CParsePreprocessorDirective(token, token_buffer,
  1085.                                             outfile, infname, flags);
  1086.             }
  1087.             else {
  1088.  
  1089.                 /* only count open brace, parens and brackets within blocks
  1090.                  * of one element of an ifdef code block */
  1091.                 if (!token->else_nesting_level) {
  1092.                     if (strchr(open_brace, token->cur_token[0])) {
  1093.                         nesting_level++;
  1094.                     }
  1095.                     else {
  1096.                         if (strchr(close_brace, token->cur_token[0])) {
  1097.                             nesting_level--;
  1098.                         }
  1099.                     }
  1100.                 }
  1101.             }
  1102.         }
  1103.         else
  1104.             nesting_level = 0;
  1105.     }
  1106. }
  1107.  
  1108.  
  1109. /*----------------------------------------------------------------------------
  1110.  *
  1111.  * CToPunctuator() will parse tokens until the next punctuator has been
  1112.  * reached.  If tokens are no longer available this loop will stop.  If this
  1113.  * loop is successful the found flag declared in the host routine will be
  1114.  * set.
  1115.  *
  1116.  ---------------------------------------------------------------------------*/
  1117.  
  1118. BOOLEAN CToPunctuator(Token * token, Buffer * token_buffer, FILE * outfile,
  1119.                        char *infname, Flags * flags)
  1120. {
  1121.     BOOLEAN punctuator_found;
  1122.  
  1123.     /* init and parse through until the first punctuator is found */
  1124.     token->token_count = 0;
  1125.     punctuator_found = FALSE;
  1126.     while (!punctuator_found) {
  1127.         token->token_count++;
  1128.         CTokenSwap(token);
  1129.         if (!CNextToken(token, token_buffer, outfile, infname, flags)) {
  1130.             break;
  1131.         }
  1132.         else {
  1133.             if (IsPunctuator(token->cur_token[0]))
  1134.                 punctuator_found = TRUE;
  1135.         }
  1136.     }
  1137.  
  1138.     /* return value */
  1139.     return punctuator_found;
  1140. }
  1141.  
  1142.  
  1143. /*----------------------------------------------------------------------------
  1144.  *
  1145.  * CParseParens() will move through a declaration in parentheses and place
  1146.  * the correct valid token as prev_token.  This return TRUE if a '[' was seen
  1147.  * within the parens and false otherwise.
  1148.  *
  1149.  ---------------------------------------------------------------------------*/
  1150.  
  1151. BOOLEAN CParseParens(Token * token, Buffer * token_buffer, FILE * outfile,
  1152.                       char *infname, Flags * flags)
  1153. {
  1154.     BOOLEAN token_found;
  1155.     BOOLEAN variable_seen;
  1156.     int brace_ignore = 1;
  1157.  
  1158.     token->else_nesting_level = 0;
  1159.  
  1160.     token_found = TRUE;
  1161.     variable_seen = FALSE;
  1162.     while (brace_ignore &&
  1163.            token_found) {
  1164.  
  1165.         token_found = CNextToken(token, token_buffer, outfile,
  1166.                                  infname, flags);
  1167.  
  1168.         if (token_found &&
  1169.             !token->else_nesting_level) {
  1170.             switch (token->cur_token[0]) {
  1171.  
  1172.                 case '(':
  1173.  
  1174.                     /* increment brace_ignore and continue */
  1175.                     brace_ignore++;
  1176.                     break;
  1177.  
  1178.                 case ')':
  1179.  
  1180.                     /* just decrement brace_ignore if it is positive. If
  1181.                      * brace ignore is not positive at this point then we
  1182.                      * certainly have a syntax error.  Ignore this fact if
  1183.                      * so. */
  1184.                     if (brace_ignore) {
  1185.                         brace_ignore--;
  1186.                     }
  1187.                     break;
  1188.  
  1189.                 case '[':
  1190.  
  1191.                     /* move to end of array bounds */
  1192.                     variable_seen = TRUE;
  1193.                     CToLevelZero(token, token_buffer, outfile,
  1194.                                  infname, flags);
  1195.                     break;
  1196.  
  1197.                 default:
  1198.                     CTokenSwap(token);
  1199.                     break;
  1200.             }
  1201.         }
  1202.     }
  1203.  
  1204.     return variable_seen;
  1205. }
  1206.  
  1207.  
  1208. /*----------------------------------------------------------------------------
  1209.  *
  1210.  * COutputCommaDelimitedToken() will output a token and then parse the
  1211.  * statement until ';' or ',' is reached.  The token is output if the passed
  1212.  * token type is requested from the command line.
  1213.  *
  1214.  ---------------------------------------------------------------------------*/
  1215.  
  1216. void COutputCommaDelimitedToken(Token * token, Buffer * token_buffer,
  1217.                                  SymbolType token_type, FILE * outfile,
  1218.                                  char *infname, Flags * flags)
  1219. {
  1220.     char open_brace[] = "{[(";  /* open brace set */
  1221.     BOOLEAN punctuator_found;
  1222.  
  1223.     /* output the token */
  1224.     COutputToken(token, token_buffer, token_type,
  1225.                  outfile, infname, flags);
  1226.  
  1227.     /* go to the next list punctuator (',' or ';') */
  1228.     punctuator_found = TRUE;
  1229.     while (token->cur_token[0] != ',' &&
  1230.            token->cur_token[0] != ';' &&
  1231.            punctuator_found) {
  1232.         if (strchr(open_brace, token->cur_token[0])) {
  1233.             CToLevelZero(token, token_buffer, outfile, infname, flags);
  1234.         }
  1235.         punctuator_found = CToPunctuator(token, token_buffer, outfile,
  1236.                                          infname, flags);
  1237.     }
  1238. }
  1239.  
  1240.  
  1241. /*----------------------------------------------------------------------------
  1242.  *
  1243.  * CParseCommaDelimitedList() will parse a token list seperated by commas
  1244.  * until a ';' is found.  The tokens are output if the passed type is
  1245.  * requested from the command line.
  1246.  *
  1247.  ---------------------------------------------------------------------------*/
  1248.  
  1249. void CParseCommaDelimitedList(Token * token, Buffer * token_buffer,
  1250.                                SymbolType token_type, FILE * outfile,
  1251.                                char *infname, Flags * flags)
  1252. {
  1253.     char open_brace[] = "{[(";  /* open brace set */
  1254.     BOOLEAN punctuator_found;
  1255.  
  1256.     /* parse through the list */
  1257.     punctuator_found = TRUE;
  1258.     while (token->cur_token[0] != ';' &&
  1259.            punctuator_found) {
  1260.         punctuator_found = CToPunctuator(token, token_buffer, outfile,
  1261.                                          infname, flags);
  1262.         if (punctuator_found) {
  1263.             switch (token->cur_token[0]) {
  1264.  
  1265.                 case '(':
  1266.  
  1267.                     /* this is an embedded variable declaration, either a
  1268.                      * complex variable pointer or function pointer, fall
  1269.                      * through after picking out the internal token */
  1270.                     CParseParens(token, token_buffer, outfile,
  1271.                                  infname, flags);
  1272.  
  1273.                 case '[':
  1274.                 case ',':
  1275.                 case ';':
  1276.                 case '=':
  1277.  
  1278.                     /* this is one of the proper ending tokens for this type
  1279.                      * of declaration list, so output it and parse to the
  1280.                      * next correct punctuator */
  1281.                     COutputToken(token, token_buffer, token_type,
  1282.                                  outfile, infname, flags);
  1283.                     while (token->cur_token[0] != ',' &&
  1284.                            token->cur_token[0] != ';' &&
  1285.                            punctuator_found) {
  1286.                         if (strchr(open_brace, token->cur_token[0])) {
  1287.                             CToLevelZero(token, token_buffer, outfile,
  1288.                                          infname, flags);
  1289.                         }
  1290.                         punctuator_found = CToPunctuator(token, token_buffer,
  1291.                                                          outfile, infname,
  1292.                                                          flags);
  1293.                     }
  1294.                     break;
  1295.                 default:
  1296.                     break;
  1297.             }
  1298.         }
  1299.     }
  1300. }
  1301.  
  1302.  
  1303. /*----------------------------------------------------------------------------
  1304.  *
  1305.  * CParseFunctionOrGlobalVariable() will parse a function, prototype or
  1306.  * global variable syntax.
  1307.  *
  1308.  ---------------------------------------------------------------------------*/
  1309.  
  1310. void CParseFunctionOrGlobalVariable(Token * token, Buffer * token_buffer,
  1311.                                      FILE * outfile, char *infname,
  1312.                                      Flags * flags)
  1313. {
  1314.     char buf[MAX_TOKEN_LENGTH]; /* the first token buffer */
  1315.     long int charloc;           /* the char location of sbuf1 */
  1316.     long int tokenline;         /* the line number of sbuf1 */
  1317.     long int lineoffset;        /* the line offset of sbuf1 */
  1318.  
  1319.     BOOLEAN token_found;
  1320.     BOOLEAN punctuator_found;
  1321.     BOOLEAN last_token_known;
  1322.     BOOLEAN variable_seen;
  1323.  
  1324.     /* init */
  1325.     buf[0] = '\0';
  1326.     charloc = 0;
  1327.     tokenline = 1;
  1328.     lineoffset = 0;
  1329.  
  1330.     /* save the previous token */
  1331.     last_token_known = CIsDeclarationToken(token->prev_token);
  1332.     if (!last_token_known) {
  1333.  
  1334.         /* If this is not a known token then it may be a function name. Save
  1335.          * it then look further at the syntax.  This also may be a symbol
  1336.          * previously defined via a typedef which alters the syntax of C/C++ */
  1337.         strcpy(buf, token->prev_token);
  1338.         charloc = *(token->prev_char_location);
  1339.         tokenline = *(token->prev_token_line);
  1340.         lineoffset = *(token->prev_line_offset);
  1341.     }
  1342.  
  1343.     /* This is a function or prototype or global variable go to brace_ignore
  1344.      * level zero again. */
  1345.     variable_seen = CParseParens(token, token_buffer, outfile,
  1346.                                  infname, flags);
  1347.  
  1348.     /* Check to see if this is a function, prototype, or global variable. If
  1349.      * the token is a ';' and last_token_known is false then we assume a
  1350.      * function.  Strange variable declarations may fool this, but not
  1351.      * likely. If the character is a '(' then it is certainly a function or
  1352.      * prototype unless variable_seen is TRUE, then it is a variable. If the
  1353.      * character is a '[', ',' then it is certainly a variable declaration.
  1354.      * If the character is a ';' and last_token_known is true then it is a
  1355.      * variable declaration.  If the token is anything else then it is a
  1356.      * function. */
  1357.     token_found = CNextToken(token, token_buffer, outfile, infname, flags);
  1358.     if (token_found) {
  1359.         switch (token->cur_token[0]) {
  1360.  
  1361.             case ';':
  1362.  
  1363.                 /* determine if a prototype or a variable declaration. if the
  1364.                  * last_token_known is true then it is a global variable.  If
  1365.                  * the token was a symbol defined by a typedef then this
  1366.                  * distinction is incorrect since typedef actually alters
  1367.                  * syntax.  This is correct for the large majority of cases
  1368.                  * since most do not enclose simple variable declarations in
  1369.                  * parens. */
  1370.                 if (last_token_known) {
  1371.  
  1372.                     /* this is a global variable */
  1373.                     COutputToken(token, token_buffer, GlobalVariable,
  1374.                                  outfile, infname, flags);
  1375.                 }
  1376.                 else {
  1377.  
  1378.                     /* this is a prototype, copy saved token back to
  1379.                      * prev_token, output and continue */
  1380.                     strcpy(token->prev_token, buf);
  1381.                     *(token->prev_char_location) = charloc;
  1382.                     *(token->prev_token_line) = tokenline;
  1383.                     *(token->prev_line_offset) = lineoffset;
  1384.                     COutputToken(token, token_buffer, ProtoType,
  1385.                                  outfile, infname, flags);
  1386.                 }
  1387.                 break;
  1388.  
  1389.             case '(':
  1390.  
  1391.                 if (variable_seen) {
  1392.  
  1393.                     /* this is a variable declaration */
  1394.                     COutputCommaDelimitedToken(token, token_buffer,
  1395.                                                GlobalVariable, outfile,
  1396.                                                infname, flags);
  1397.                     CParseCommaDelimitedList(token, token_buffer,
  1398.                                              GlobalVariable, outfile,
  1399.                                              infname, flags);
  1400.                 }
  1401.                 else {
  1402.  
  1403.                     /* move to level zero again */
  1404.                     CToLevelZero(token, token_buffer, outfile,
  1405.                                  infname, flags);
  1406.  
  1407.                     /* obtain the next token */
  1408.                     token_found = CNextToken(token, token_buffer, outfile,
  1409.                                              infname, flags);
  1410.  
  1411.                     if (token_found) {
  1412.  
  1413.                         /* check if prototype, function or function pointer
  1414.                          * variable declaration */
  1415.                         switch (token->cur_token[0]) {
  1416.  
  1417.                             case '=':
  1418.  
  1419.                                 /* this is a function pointer variable
  1420.                                  * declaration */
  1421.                                 COutputCommaDelimitedToken(token,
  1422.                                                            token_buffer,
  1423.                                                            GlobalVariable,
  1424.                                                            outfile,
  1425.                                                            infname, flags);
  1426.                                 CParseCommaDelimitedList(token, token_buffer,
  1427.                                                          GlobalVariable,
  1428.                                                          outfile,
  1429.                                                          infname, flags);
  1430.                                 break;
  1431.  
  1432.                             case ';':
  1433.  
  1434.                                 /* this is a prototype, output it */
  1435.                                 COutputToken(token, token_buffer, ProtoType,
  1436.                                              outfile, infname, flags);
  1437.                                 break;
  1438.  
  1439.                             default:
  1440.  
  1441.                                 /* this is a function */
  1442.                                 COutputToken(token, token_buffer, Function,
  1443.                                              outfile, infname, flags);
  1444.  
  1445.                                 /* parse through function */
  1446.                                 punctuator_found = TRUE;
  1447.                                 while (token->cur_token[0] != '{' &&
  1448.                                        punctuator_found) {
  1449.                                     punctuator_found =
  1450.                                         CToPunctuator(token, token_buffer,
  1451.                                                       outfile, infname,
  1452.                                                       flags);
  1453.                                 }
  1454.                                 if (punctuator_found) {
  1455.                                     CToLevelZero(token, token_buffer, outfile,
  1456.                                                  infname, flags);
  1457.                                 }
  1458.                                 break;
  1459.                         }
  1460.                     }
  1461.                 }
  1462.                 break;
  1463.  
  1464.             case '[':
  1465.             case '=':
  1466.             case ',':
  1467.  
  1468.                 /* global variables */
  1469.                 COutputCommaDelimitedToken(token, token_buffer,
  1470.                                            GlobalVariable, outfile,
  1471.                                            infname, flags);
  1472.                 CParseCommaDelimitedList(token, token_buffer,
  1473.                                          GlobalVariable, outfile,
  1474.                                          infname, flags);
  1475.                 break;
  1476.  
  1477.             default:
  1478.  
  1479.                 /* this is a function, copy saved token back to prev_token,
  1480.                  * output and continue */
  1481.                 strcpy(token->prev_token, buf);
  1482.                 *(token->prev_char_location) = charloc;
  1483.                 *(token->prev_token_line) = tokenline;
  1484.                 *(token->prev_line_offset) = lineoffset;
  1485.                 COutputToken(token, token_buffer, Function,
  1486.                              outfile, infname, flags);
  1487.  
  1488.                 /* parse through function */
  1489.                 punctuator_found = TRUE;
  1490.                 while (token->cur_token[0] != '{' &&
  1491.                        punctuator_found) {
  1492.                     punctuator_found =
  1493.                         CToPunctuator(token, token_buffer, outfile,
  1494.                                       infname, flags);
  1495.                 }
  1496.                 if (punctuator_found) {
  1497.                     CToLevelZero(token, token_buffer, outfile,
  1498.                                  infname, flags);
  1499.                 }
  1500.                 break;
  1501.         }
  1502.     }
  1503. }
  1504.  
  1505.  
  1506. /*----------------------------------------------------------------------------
  1507.  *
  1508.  * CParseNOP() will parse an as of yet unrecognized statement.  If I run into
  1509.  * a punctuator at this time then I have found either a structure declaration
  1510.  * (C++ 2.0), or a global variable declaration.  If the punctuator is '[',
  1511.  * ',', '=', or ';' then it is a global variable declaration.  If the
  1512.  * punctuator is a '{' then we have a structure declaration at this time we
  1513.  * should not run into any closing punctuators or syntax is in a bad way
  1514.  *
  1515.  ---------------------------------------------------------------------------*/
  1516.  
  1517. void CParseNOP(Token * token, Buffer * token_buffer, FILE * outfile,
  1518.                 char *infname, Flags * flags)
  1519. {
  1520.     BOOLEAN token_found;
  1521.  
  1522.     switch (token->cur_token[0]) {
  1523.         case ';':
  1524.         case '=':
  1525.         case ',':
  1526.         case '[':
  1527.  
  1528.             /* global variables are here */
  1529.             COutputCommaDelimitedToken(token, token_buffer,
  1530.                                        GlobalVariable, outfile,
  1531.                                        infname, flags);
  1532.             CParseCommaDelimitedList(token, token_buffer,
  1533.                                      GlobalVariable, outfile,
  1534.                                      infname, flags);
  1535.             token->extern_active = FALSE;
  1536.             token->static_active = FALSE;
  1537.             break;
  1538.  
  1539.         case '{':
  1540.  
  1541.             /* this is a structure (C++ syntax) */
  1542.             /* output it */
  1543.             COutputToken(token, token_buffer, Structure,
  1544.                          outfile, infname, flags);
  1545.  
  1546.             /* move through declaration */
  1547.             CToLevelZero(token, token_buffer, outfile, infname, flags);
  1548.  
  1549.             /* get the next token */
  1550.             token_found = CNextToken(token, token_buffer, outfile,
  1551.                                      infname, flags);
  1552.  
  1553.             /* if a token is available then output the list */
  1554.             if (token_found) {
  1555.                 CParseCommaDelimitedList(token, token_buffer,
  1556.                                          GlobalVariable, outfile,
  1557.                                          infname, flags);
  1558.             }
  1559.             token->extern_active = FALSE;
  1560.             token->static_active = FALSE;
  1561.             break;
  1562.  
  1563.         case '(':
  1564.  
  1565.             CParseFunctionOrGlobalVariable(token, token_buffer, outfile,
  1566.                                            infname, flags);
  1567.             token->extern_active = FALSE;
  1568.             token->static_active = FALSE;
  1569.             break;
  1570.  
  1571.         default:
  1572.  
  1573.             /* true NOP */
  1574.             break;
  1575.     }
  1576. }
  1577.  
  1578.  
  1579. /*----------------------------------------------------------------------------
  1580.  *
  1581.  * CParseEnumerationConstants() will parse constants within an enumeration
  1582.  * declaration 
  1583.  *
  1584.  ---------------------------------------------------------------------------*/
  1585.  
  1586. void CParseEnumerationConstants(Token *token, Buffer *token_buffer, 
  1587.                                 FILE *outfile, char *infname, 
  1588.                                 Flags *flags)
  1589. {        
  1590.     BOOLEAN punctuator_found;
  1591.  
  1592.     char open_brace[] = "({[";
  1593.     
  1594.     /* obtain the enumeration constants */
  1595.     punctuator_found = TRUE;
  1596.     
  1597.     while (token->cur_token[0] != '}' &&
  1598.            punctuator_found) {
  1599.         punctuator_found = CToPunctuator(token, token_buffer, outfile,
  1600.                                          infname, flags);
  1601.         if (punctuator_found) {
  1602.             switch (token->cur_token[0]) {
  1603.  
  1604.                 case ',':
  1605.                 case '=':
  1606.  
  1607.                     /* this is one of the proper ending tokens for this type
  1608.                      * of declaration list, so output it and parse to the
  1609.                      * next correct punctuator */
  1610.                     COutputToken(token, token_buffer, EnumerationConstant,
  1611.                                  outfile, infname, flags);
  1612.                     while (token->cur_token[0] != ',' &&
  1613.                            token->cur_token[0] != '}' &&
  1614.                            punctuator_found) {
  1615.                         if (strchr(open_brace, token->cur_token[0])) {
  1616.                             CToLevelZero(token, token_buffer, outfile,
  1617.                                          infname, flags);
  1618.                         }
  1619.                         punctuator_found = CToPunctuator(token, token_buffer,
  1620.                                                          outfile, infname,
  1621.                                                          flags);
  1622.                     }
  1623.                     break;
  1624.                     
  1625.                 default:
  1626.                     break;
  1627.             }
  1628.         }
  1629.     }
  1630. }
  1631.     
  1632.  
  1633. /*----------------------------------------------------------------------------
  1634.  *
  1635.  * CParseDeclarationStatement() will parse struct, enum and union
  1636.  * declarations.  take the token just before the first punctuator, run
  1637.  * through the top level braces and parse for variables if the first
  1638.  * punctuator is a ';' then this is a global variable declaration, if the
  1639.  * first token[0] is a '{' then this is a global variable declaration.
  1640.  *
  1641.  ---------------------------------------------------------------------------*/
  1642.  
  1643. void CParseDeclarationStatement(Token * token, Buffer * token_buffer,
  1644.                                  SymbolType type, FILE * outfile,
  1645.                                  char *infname, Flags * flags)
  1646. {
  1647.     BOOLEAN token_found;
  1648.     BOOLEAN punctuator_found;
  1649.     BOOLEAN primary_parse;
  1650.  
  1651.     punctuator_found = CToPunctuator(token, token_buffer, outfile,
  1652.                                      infname, flags);
  1653.     if (punctuator_found) {
  1654.  
  1655.         /* init */
  1656.         primary_parse = TRUE;
  1657.  
  1658.         /* switch on current token */
  1659.         switch (token->cur_token[0]) {
  1660.  
  1661.                 /* this is truly an object declaration */
  1662.             case '{':
  1663.  
  1664.                 /* output only if this is not a variable declaration */
  1665.                 if (token->token_count != 1) {
  1666.  
  1667.                     /* output it */
  1668.                     COutputToken(token, token_buffer, type,
  1669.                                  outfile, infname, flags);
  1670.                 }
  1671.  
  1672.                 /* check if enumeration */
  1673.                 if (token->token_count != 1 &&
  1674.                     type == Enumeration) {
  1675.  
  1676.                     CParseEnumerationConstants(token, token_buffer, 
  1677.                                                outfile, infname, flags);
  1678.                 }
  1679.                 else {
  1680.  
  1681.                     /* move through declaration and fall through */
  1682.                     CToLevelZero(token, token_buffer, outfile, infname, flags);
  1683.                 }
  1684.  
  1685.                 /* get the next token, if one not available then break out of
  1686.                  * case */
  1687.                 token_found = CNextToken(token, token_buffer, outfile,
  1688.                                          infname, flags);
  1689.                 if (!token_found)
  1690.                     break;
  1691.  
  1692.                 /* fall through to take care of variable declarations after
  1693.                  * setting pre-parse flag */
  1694.                 primary_parse = FALSE;
  1695.  
  1696.             case ';':
  1697.             case '=':
  1698.             case ',':
  1699.             case '[':
  1700.  
  1701.                 /* if this is the first seen then output it */
  1702.                 if (primary_parse) {
  1703.                     COutputCommaDelimitedToken(token, token_buffer,
  1704.                                                GlobalVariable,
  1705.                                                outfile, infname,
  1706.                                                flags);
  1707.                 }
  1708.  
  1709.                 CParseCommaDelimitedList(token, token_buffer,
  1710.                                          GlobalVariable,
  1711.                                          outfile, infname,
  1712.                                          flags);
  1713.  
  1714.                 break;
  1715.  
  1716.             case '(':
  1717.  
  1718.                 CParseFunctionOrGlobalVariable(token, token_buffer,
  1719.                                                outfile, infname, flags);
  1720.                 break;
  1721.  
  1722.             default:
  1723.  
  1724.                 /* not reached */
  1725.                 break;
  1726.         }
  1727.     }
  1728. }
  1729.  
  1730.  
  1731. /*----------------------------------------------------------------------------
  1732.  *
  1733.  * CParseTypeDefinition() parses the typedef statement.  take the token just
  1734.  * before the first *correct* punctuator, the ';', ',' or the '['.  Tag any
  1735.  * declarations being done here, get the next token
  1736.  *
  1737.  ---------------------------------------------------------------------------*/
  1738.  
  1739. void CParseTypeDefinition(Token * token, Buffer * token_buffer, FILE * outfile,
  1740.                            char *infname, Flags * flags)
  1741. {
  1742.     BOOLEAN token_found;
  1743.     BOOLEAN parens_found;
  1744.     BOOLEAN special_found;
  1745.  
  1746.     int token_count;
  1747.     SymbolType tmptype;
  1748.  
  1749.     token_found = CNextToken(token, token_buffer, outfile, infname, flags);
  1750.  
  1751.     if (token_found) {
  1752.  
  1753.         /* check the type of the token for future use */
  1754.         tmptype = CTokenType(token->cur_token);
  1755.  
  1756.         /* parse the typedef */
  1757.         parens_found = FALSE;
  1758.         special_found = FALSE;
  1759.         token_count = 0;
  1760.         while (token->cur_token[0] != ';' &&
  1761.                token->cur_token[0] != ',' &&
  1762.                token->cur_token[0] != '[' &&
  1763.                token_found &&
  1764.                !special_found) {
  1765.  
  1766.             /* parse for defines */
  1767.             if (token_found) {
  1768.  
  1769.                 /* handle the punctuators */
  1770.                 switch (token->cur_token[0]) {
  1771.  
  1772.                     case '{':
  1773.  
  1774.                         /* pass through any defines going on here */
  1775.                         if (token->cur_token[0] == '{') {
  1776.  
  1777.                             /* if the token count is > 1 here then we have a
  1778.                              * named declaration and need to output the
  1779.                              * token, output only if the token type is enum,
  1780.                              * struct, or union */
  1781.                             if (token_count > 1 &&
  1782.                                 (tmptype == Structure ||
  1783.                                  tmptype == Enumeration ||
  1784.                                  tmptype == Union)) {
  1785.                                 COutputToken(token, token_buffer,
  1786.                                              tmptype, outfile,
  1787.                                              infname, flags);
  1788.                             }
  1789.  
  1790.                             if (tmptype == Enumeration) {
  1791.  
  1792.                                 CParseEnumerationConstants(token,
  1793.                                                            token_buffer, 
  1794.                                                            outfile, infname, 
  1795.                                                            flags);
  1796.                             }
  1797.                             else {
  1798.  
  1799.                                 /* go back to level 0 */
  1800.                                 CToLevelZero(token, token_buffer, outfile,
  1801.                                              infname, flags);
  1802.                             }
  1803.                         }
  1804.                         break;
  1805.  
  1806.                     case '(':
  1807.  
  1808.                         /* if this is the top level and we have already been
  1809.                          * through a set of parens then we know this to be a
  1810.                          * function typedef so we output the previous token,
  1811.                          * otherwise check the previous token and if it is a
  1812.                          * known keyword then just eat the token and continue
  1813.                          * on our way */
  1814.                         if (parens_found) {
  1815.                             COutputToken(token, token_buffer,
  1816.                                          TypeDefinition, outfile,
  1817.                                          infname, flags);
  1818.                             CToLevelZero(token, token_buffer, outfile,
  1819.                                          infname, flags);
  1820.                             special_found = TRUE;
  1821.                         }
  1822.                         else {
  1823.  
  1824.                             /* Move back to the top level */
  1825.                             CParseParens(token, token_buffer, outfile,
  1826.                                          infname, flags);
  1827.  
  1828.                             /* next paren we find we know we have a token */
  1829.                             parens_found = TRUE;
  1830.  
  1831.                             /* swap to prevent loss of token */
  1832.                             CTokenSwap(token);
  1833.                         }
  1834.                         break;
  1835.  
  1836.                     default:
  1837.  
  1838.                         /* if we have another token after a paren parse then
  1839.                          * we know the token in the parens was nothing
  1840.                          * special */
  1841.                         parens_found = FALSE;
  1842.                         break;
  1843.                 }
  1844.             }
  1845.  
  1846.             /* get another token */
  1847.             CTokenSwap(token);
  1848.             token_found = CNextToken(token, token_buffer, outfile,
  1849.                                      infname, flags);
  1850.             token_count++;
  1851.         }
  1852.  
  1853.         /* output the typedef names if appropriate */
  1854.         if (token->prev_token[0] != '}' &&
  1855.             token_found) {
  1856.  
  1857.             /* don't output the first token if already done */
  1858.             if (!special_found) {
  1859.                 COutputCommaDelimitedToken(token, token_buffer,
  1860.                                            TypeDefinition, outfile,
  1861.                                            infname, flags);
  1862.             }
  1863.  
  1864.             /* parse through the rest of the typedef names */
  1865.             CParseCommaDelimitedList(token, token_buffer,
  1866.                                      TypeDefinition, outfile,
  1867.                                      infname, flags);
  1868.         }
  1869.     }
  1870. }
  1871.  
  1872.  
  1873. /*----------------------------------------------------------------------------
  1874.  *
  1875.  * CParseClass() will parse the C++ class syntax.  take the token just before
  1876.  * the first '{', ',' or ':' and run through the top level braces if there
  1877.  *
  1878.  ---------------------------------------------------------------------------*/
  1879.  
  1880. void CParseClass(Token * token, Buffer * token_buffer, FILE * outfile,
  1881.                   char *infname, Flags * flags)
  1882. {
  1883.     BOOLEAN token_found;
  1884.  
  1885.     token_found = TRUE;
  1886.     while (token->cur_token[0] != '{' &&
  1887.            token->cur_token[0] != ':' &&
  1888.            token->cur_token[0] != ';' &&
  1889.            token_found) {
  1890.  
  1891.         /* save the current token */
  1892.         CTokenSwap(token);
  1893.  
  1894.         /* get the next token */
  1895.         token_found = CNextToken(token, token_buffer, outfile,
  1896.                                  infname, flags);
  1897.     }
  1898.  
  1899.     /* output the class name */
  1900.     if (token_found) {
  1901.         COutputToken(token, token_buffer, Class,
  1902.                      outfile, infname, flags);
  1903.  
  1904.         /* parse through the remainder of the statement */
  1905.         while (token->cur_token[0] != ';' &&
  1906.                token_found) {
  1907.             if (token->cur_token[0] == '{') {
  1908.  
  1909.                 /* move back to the zero level */
  1910.                 CToLevelZero(token, token_buffer, outfile, infname, flags);
  1911.             }
  1912.  
  1913.             token_found = CNextToken(token, token_buffer, outfile,
  1914.                                      infname, flags);
  1915.         }
  1916.     }
  1917. }
  1918.  
  1919.  
  1920. /*----------------------------------------------------------------------------
  1921.  *
  1922.  * CTags() tags an input stream assuming standard ANSI 2.0 C/C++ syntax.
  1923.  * Long tokens are allowed, ANSI requires only 31 significant.
  1924.  *
  1925.  ---------------------------------------------------------------------------*/
  1926.  
  1927. void CTags(FILE * infile, char *infname, FILE * outfile, Flags * flags)
  1928. {
  1929.     SymbolType type;            /* the type of the current token */
  1930.  
  1931.     Buffer input_buffer;        /* the file buffer and state, stack alloc */
  1932.     Buffer *token_buffer = &input_buffer;       /* a convenient pointer */
  1933.  
  1934.     Token token_state;          /* the token state, stack alloc */
  1935.     Token *token = &token_state;/* a convenient pointer to token state */
  1936.  
  1937.     BOOLEAN token_found;        /* set by CNextToken() */
  1938.  
  1939.     /* init the parser engine */
  1940.     CParserInit();
  1941.     token->token_count = 0;
  1942.  
  1943.     /* init the current token buffers */
  1944.     token->cur_token = token->sbuf1;
  1945.     token->cur_char_location = &(token->charloc1);
  1946.     token->cur_token_line = &(token->tokenline1);
  1947.     token->cur_token[0] = '\0';
  1948.     token->cur_line_offset = &(token->lineoffset1);
  1949.     *(token->cur_char_location) = 0;
  1950.     *(token->cur_token_line) = 1;
  1951.     *(token->cur_line_offset) = 0;
  1952.  
  1953.     /* init the previous token buffers */
  1954.     token->prev_token = token->sbuf2;
  1955.     token->prev_char_location = &(token->charloc2);
  1956.     token->prev_token_line = &(token->tokenline2);
  1957.     token->prev_token[0] = '\0';
  1958.     token->prev_line_offset = &(token->lineoffset2);
  1959.     *(token->prev_char_location) = 0;
  1960.     *(token->prev_token_line) = 1;
  1961.     *(token->prev_line_offset) = 0;
  1962.  
  1963.     /* init the input buffers */
  1964.     token_buffer->token_char_location = 0;
  1965.     token_buffer->token_line_location = 1;
  1966.     token_buffer->token_line_offset = 0;
  1967.     token_buffer->Cbuf[0] = '\0';
  1968.     token_buffer->buffer = token_buffer->Cbuf;
  1969.     token_buffer->infile = infile;
  1970.  
  1971.     /* init Extern and Static states */
  1972.     token->extern_active = FALSE;
  1973.     token->static_active = FALSE;
  1974.  
  1975.     /* get the first token */
  1976.     token_found = CNextToken(token, token_buffer, outfile, infname, flags);
  1977.  
  1978.     /* loop through the file */
  1979.     while (token_found) {
  1980.  
  1981.         /* obtain the token type */
  1982.         type = CTokenType(token->cur_token);
  1983.  
  1984.         /* react on the token type */
  1985.         switch (type) {
  1986.  
  1987.             case NOP:
  1988.                 CParseNOP(token, token_buffer, outfile, infname, flags);
  1989.                 break;
  1990.  
  1991.             case Structure:
  1992.             case Enumeration:
  1993.             case Union:
  1994.                 CParseDeclarationStatement(token, token_buffer, type,
  1995.                                            outfile, infname, flags);
  1996.                 break;
  1997.  
  1998.             case TypeDefinition:
  1999.                 CParseTypeDefinition(token, token_buffer, outfile,
  2000.                                      infname, flags);
  2001.                 break;
  2002.  
  2003.             case Class:
  2004.                 CParseClass(token, token_buffer, outfile, infname, flags);
  2005.                 break;
  2006.  
  2007.             case Extern:
  2008.                 token->extern_active = TRUE;
  2009.                 break;
  2010.  
  2011.             case Static:
  2012.                 token->static_active = TRUE;
  2013.                 break;
  2014.  
  2015.             default:
  2016.                 /* not reached */
  2017.                 break;
  2018.         }
  2019.  
  2020.         if (type != Extern &&
  2021.             type != Static &&
  2022.             type != NOP) {
  2023.  
  2024.             /* turn off the extern and static flag */
  2025.             token->extern_active = FALSE;
  2026.             token->static_active = FALSE;
  2027.         }
  2028.  
  2029.         /* swap state variables and get the next token */
  2030.         CTokenSwap(token);
  2031.         token_found = CNextToken(token, token_buffer, outfile,
  2032.                                  infname, flags);
  2033.     }
  2034. }
  2035.